<?php
/**
 * Date: 2017/12/25
 * Time: 17:38
 * Author: zeronlee
 */

namespace App\Services\ChartAnalysis;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;
use App\Models\Ogz;
use App\Models\Flaw\Vuls;
use App\Models\Flaw\Level;

class ChartAnalysis
{
    /**
     * 时间筛选
     * @var bool
     */
    private $timeVaild = false;

    /**
     * 开始时间
     * @var string
     */
    public $startime;

    /**
     * 结束时间
     * @var string
     */
    public $endTime;

    /**
     * 报表数据
     * @var mixed
     */
    public $data;

    public function __construct () {
        $this->data = new Data();
    }

    /**
     * 关联机构下#饼图
     * 获取漏洞状态统计
     */
    public function getPieByStatus ($pid) {
        $res = [];
        $i = 0;
        $plates = $this->data->getComposition($pid);

        foreach ($plates as $plate) {
            //时间检索参数
            $this->setTimeParam();
            $appIds = $plate['apps']->pluck('id')->toArray();
            if($appIds){
                $confirm = $this->data->getConfirmedNum(0,[Vuls::SOLVED,Vuls::CLOSED],$appIds);
                $count   = $this->data->getTotal(0,$appIds);
            } else {

                $confirm = $this->data->getConfirmedNum($plate['oid']);
                //漏洞总数
                $count = $this->data->getTotal($plate['oid']);
            }
            //剔除没有数据的
            if ($confirm <= 0 && $count <= 0) {
                continue;
            }
            $res[$i]['oid']   = $plate['oid'];
            $res[$i]['oname'] = $plate['oname'];
            //首页嵌套图表现形式处理-已修复
            $res[$i]['confirm_index'] = [
                'value' => $confirm,
                'name' => $plate['oname']
            ];
            //首页嵌套图表现形式处理-总数
            $res[$i]['count_index'] = [
                'value' => $count,
                'name' => $plate['oname']
            ];
            $i++;
        }

        return $res;
    }

    /**
     * 关联机构下
     * 获取柱状图发现总数
     * @param $pid
     */
    public function getGraphByNum ($pid) {
        $res = [];

        $i = 0;
        $ogz = new Ogz();
        $plates = $this->data->getComposition($pid);
        foreach ($plates as $plate) {

            $this->setTimeParam();

            $appIds = $plate['apps']->pluck('id')->toArray();
            if($appIds){
                $high = $this->data->getFindNum([
                    Level::SERIOUSID
                ],0,$appIds);
                $secondary = $this->data->getFindNum([Level::HIGHRISKID],0,$appIds);

                $low = $this->data->getFindNum([Level::INRISKID,Level::LOWID,Level::NOEFFECT], 0,$appIds);
            } else {

                $high = $this->data->getFindNum([
                    Level::SERIOUSID
                ],$plate['oid']);
                $secondary = $this->data->getFindNum([Level::HIGHRISKID],$plate['oid']);

                $low = $this->data->getFindNum([Level::INRISKID,Level::LOWID,Level::NOEFFECT], $plate['oid']);
            }
            //剔除没有数据的
            if ($high <= 0 && $secondary <= 0 && $low <= 0) {
                continue;
            }

            $res[$i]['oid']   = $plate['oid'];
            $res[$i]['oname'] = $plate['oname'];
            $res[$i]['high'] = $high;

            $res[$i]['secondary'] = $secondary;
            $res[$i]['low'] = $low;
            //跳转子板块标识
            if($ogz->hasChild($plate['oid'])){
                $res[$i]['jumpSub'] = true;
            } else{
                $res[$i]['jumpSub'] = false;
            }

            $i++;
        }
        return $res;
    }

    /**
     * 关联机构下
     * 板块漏洞总数
     * 和修复总数
     * @param $pid
     */
    public function getTacByTime ($pid) {
        $res = [];

        $i = 0;
        $plates = $this->data->getComposition($pid);
        foreach ($plates as $plate) {

            $res[$i]['oid']   = $plate['oid'];
            $res[$i]['oname'] = $plate['oname'];
            $this->setTimeParam();
            //发现趋势
            $_total = $this->data->getTotal($plate['oid']);
            //修复情况
            $_confirmed = $this->data->getConfirmedNum($plate['oid']);

            $res[$i]['total'] = $_total;
            $res[$i]['confirmed'] = $_confirmed;

            //首页嵌套图表现形式处理-已修复
            $res[$i]['total_index'] = [
                'value' => $_total,
                'name' => $plate['oname']
            ];
            //首页嵌套图表现形式处理-总数
            $res[$i]['confirmed_index'] = [
                'value' => $_confirmed,
                'name' => $plate['oname']
            ];

            $i++;
        }
        return $res;


    }

    /**
     * 时间段设置
     */
    public function setTime () {
        // $set = env('CHART_SCOPE');
        $ret = [];
        $set = explode('-', env('CHART_SCOPE'));
        switch ($set[0]) {
            case 'day':
                for ($i = $set[1]; $i > 0; $i--) {

                    $ret[$i]['start'] = Carbon::now()->subDays($i)->startOfDay();
                    $ret[$i]['end'] = Carbon::now()->subDays($i)->endOfDay();
                }
                break;
            case 'month':
                for ($i = $set[1]; $i > 0; $i--) {

                    $ret[$i]['start'] = Carbon::now()->subMonth($i)->startOfMonth();
                    $ret[$i]['end'] = Carbon::now()->subMonth($i)->endOfMonth();
                }
                break;
            //....
        }
        return $ret;
    }

    /**
     * 柱状图统计时间
     * eg:30天内的或3月内的
     */
    public function setTime2 () {
        // $set = env('CHART_SCOPE');
        $ret = [];
        $set = explode('-', env('CHART_SCOPE'));
        switch ($set[0]) {
            case 'day':
                $ret['start'] = Carbon::now()->subDays($set[1])->startOfDay();
                $ret['end'] = Carbon::now()->subDays(1)->endOfDay();

                break;
            case 'month':
                $ret['start'] = Carbon::now()->subMonths($set[1])->startOfMonth();
                $ret['end'] = Carbon::now()->subMonths(1)->endOfMonth();

                break;
            //....
        }
        return $ret;
    }

    /**
     * 分类下
     * 获取漏洞类型和数量饼图
     * @param $pid
     */
    public function getPieByType ($pid) {
        $res = [];
        $this->setTimeParam();
        //相应权限对应的app
        $tempApp = $this->data->getAppComplex($pid);
        //漏洞类型
        $cate = $this->data->getCategory($tempApp);
        //类别
        foreach ($cate as $k => $v) {
            $res[$k]['id'] = $v->id;
            $pname = $this->data->getPcateName($v->pid);
            if ($pname){
                $v->name = $pname .'-'.$v->name;
            }
            $res[$k]['name'] = $v->name;

            $res[$k]['count'] = $v->num;
            $res[$k]['value_index'] = [
                'value' => $v->num,
                'name' => $v->name
            ];
        }
        return $res;
    }

    /**
     * 时间下
     * 发现趋势和修复情况曲线图
     */
    public function getDiagram ($pid) {
        $time = [
            'type' => explode('-', env('CHART_SCOPE'))[0],
            'data' => ['time' => [], 'new' => [], 'confirmed' => []]
        ];
        $this->data->getAppComplex($pid);

        if ($this->timeVaild) {
            //如果选择了对应的时间,从时间计算天数
            $endTime  = Carbon::parse($this->endTime)->endOfDay();
            $startime = Carbon::parse($this->startime)->startOfDay();
            //没有选择具体的时间，开始和结束时间相同是一天
            $day = $endTime->diffInDays($startime);
            if ($day < 0) {
                throw new \Exception('筛选时间有误');
            }
            $ret = [];
            //处理时间格式
            for ($i = $day; $i >= 0; $i--) {

                $ret[$i]['start'] = Carbon::now()->subDays($i)->startOfDay();
                $ret[$i]['end']   = Carbon::now()->subDays($i)->endOfDay();
            }
            $ret = array_reverse($ret);
        } else {
            //默认30天
            $ret = array_reverse($this->setTime(), true);
        }

        foreach ($ret as $k => $v) {

            //如果带上status条件 更新了之后则数据变化
            $new = $this->data->getVulByTime('created_at',$v['start'],$v['end']);

            $confirmedObj = $this->data->getVulByTimeRetBuilder('updated_at',$v['start'],$v['end']);
            $confirmed = $confirmedObj->whereIn('status',[Vuls::CONFIRMED,Vuls::SOLVED,Vuls::CLOSED])->count();

            $time['data']['time'][]      = $k;
            $time['data']['new'][]       = $new;
            $time['data']['confirmed'][] = $confirmed;

        }
        return $time;
    }

    /**
     * 级别下
     * 获取级别数据
     */
    public function getGraphByLevel ($pid) {
        $ret   = [];
        $other = [];
        $i = 0;
        //相应权限对应的app
        $this->data->getAppComplex($pid);

        $levelData = $this->data->getLevel();
        foreach ($levelData as $levels => $level) {

            $ret[$i]['id']   = $level->id;
            $ret[$i]['name'] = $level->name;
            $this->setTimeParam();
            $total = $this->data->getFindNum(['level_id' => $level->id],$pid);

            $confirmed = $this->data->getConfirmedNumByLevel($level->id);

            //漏洞总数
            $other['total'][] = $ret[$i]['total'] = $total;
            //修复数
            $other['confirmed'][] = $ret[$i]['confirmed'] = $confirmed;

            $other['name'][] = $level->name;
            $i++;
        }
        return ['ret' => $ret, 'other' => $other];
    }

    /**
     * 激活时间过滤
     */
    public function setTimeVaild () {
        $this->timeVaild = true;
    }

    /**
     * 取消时间过滤
     */
    public function setTimeVaildOut () {
        $this->timeVaild = false;
    }

    /**
     * 获取当前检索是否包含时间过滤条件
     */
    public function getTimeVaild () {
        return $this->timeVaild;
    }

    /**
     * 设置时间参数
     */
    private function setTimeParam () {
        if ($this->timeVaild) {

            $this->data->timeVaild = true;
            $this->data->startime  = $this->startime;
            $this->data->endTime   = $this->endTime;
        }
    }
}